﻿using System;
using System.Collections.Generic;
using System.Configuration;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using YmtAuth.Common.Extend;
using YmtAuth.Domain.Model.BlacklistUser;
using YmtAuth.Domain.Repository;
using YmtSystem.CrossCutting;

namespace YmtAuth.Domain.Model.Safe
{
    public class UserLoginParameter
    {
        public int UserId { get; set; }
        public string LoginId { get; set; }
        public string Source { get; set; }
        public string Ip { get; set; }
        public string DeviceId { get; set; }
        public string AppClientId { get; set; }

        public string RequestId { get; set; }

        /// <summary>
        /// 安全策略类型; pc, app
        /// </summary>
        public string StrategyType { get; set; }

        /// <summary>
        /// 设备号的标识（由个推服务器产生（通过app上的个推SDK获取），用于向设备推送消息）
        /// </summary>
        public string ClientId { get; set; }

        /// <summary>
        /// 请求接口ID
        /// </summary>
        public int ApiId { get; set; }
    }
    public class UserLoginAuthRepository
    {
        public IYmtUserLoginHistoryRepository LoginHistoryRepo { get;  set; }
        public IIpAreaInfoRepository IpAreaRepo { get;  set; }
        public IUserDeviceAuthRepository DeviceRepo { get;  set; }
        public IBlackListRepository IpBlackListRepo { get;  set; }
        public IDeviceTokenAuthRepository DeviceTokenRepo { get;  set; }
        public IIpAreaTokenRepository IpAreaTokenRepo { get; set; }
    }    
    public class AuthSafeConfiguration
    {        
        public IDictionary<string, string> SafeCfg { get; set; }
        public IDictionary<string, string> BlackCfg { get; set; }
    }     

    public class AuthSafeHandleFactory
    {
        private static readonly Dictionary<string, SortedList<int, SafeVerifyStrategyBase>> ActionList =
            new Dictionary<string, SortedList<int, SafeVerifyStrategyBase>>();
        private static readonly string App = "app";
        private static readonly string Default = "default";
        private static readonly string BuyerPc = "buyerpc";
        private static readonly string BuyerApp = "buyerapp";
        private static readonly string SellerPc = "sellerpc";
        private static readonly string SellerApp = "sellerapp";
        private static readonly string SkipVerify = "skipverify";

        public static void RegisterHandle()
        {
            //TODO PC&APP按顺序注册安全认证流程
            //TODO 注册PC端登录安全策略
#region
            //<summary>
            //PC端登录安全策略
            //1. 总开关检查; LoginSafe_Pc_Open
            //2. 检查部分策略启用安全认证策略; LoginSafe_Partial_Mode
            //3. 登录历史密码错误检查; LoginSafe_PcLoginPas_Check, LoginSafe_PcLoginPas_CheckSpec（计数器服务、mongodb统计数据--Ymt_LoginHistory.LoginHistory）
            //【身份认证】: NeedIdentityVerify_LoginPasswordHistoryVerify
            //   a. LoginSafe_PcLoginPas_Check = 1
            //   b. 登录历史密码错误-3分钟内大于等于5 => LoginSafe_PcLoginPas_CheckSpec
            //4. IP 黑名单验证; LoginSafe_PcBlacklist_Check; (mongodb-Ymt_BlacklistUser_201410.YmatouBlacklist_Ip), LoginSafe_PcBlacklist_BlacklistAction
            //【身份认证】、【拒绝登录】: NeedIdentityVerify_LoginSafe_BlackIPVerify
            //   a. LoginSafe_PcBlacklist_Check = 1
            //   b. IP禁止访问时间未过期，不在白名单，LoginSafe_PcBlacklist_BlacklistAction = 100

            //5. IP区域检查; 
            //5.1) LoginSafe_PcIp_ExistsCheck
            //5.2) Ip为空；LoginSafe_PcIp_NotExistsIdentityVerify
            //【身份认证】: NeedIdentityVerify_LoginSafe_IPNotExists
            //   a. LoginSafe_PcIp_ExistsCheck = 1
            //   b. Ip为空（IP不存在）
            //   c. LoginSafe_PcIp_NotExistsIdentityVerify = 100

            //5.3) 根据Ip获取IP区域原始数据,不存在则不需要身份验证
            //5.4) 开启用户第一次登录（LoginSafe_PcUserFirstLogin_AutoAuthSuccess），自动初始化该IP为常用登录Ip; mysql-ymatouusersafe.useripauth
            //5.5) 获取IP区域认证数据,不存在则需要身份验证 -- LoginSafe_PcIp_NotExistsIdentityVerify
            //【身份认证】: NeedIdentityVerify_LoginSafe_CannotFindIpArea
            //   a. LoginSafe_PcIp_ExistsCheck = 1
            //   b. Ip不为空
            //   c. IP库原始数据存在
            //   d. LoginSafe_PcUserFirstLogin_AutoAuthSuccess = 0 或者 LoginSafe_PcUserFirstLogin_AutoAuthSuccess = 1 && 用户不是第一次登录（用户IP区域认证数据存在）
            //   e. 用户IP区域认证数据不存在 && LoginSafe_PcIp_NotExistsIdentityVerify = 100

            //5.6) IP 黑名单验证
            //【身份认证】: TODO 待优化
            //   a. LoginSafe_PcIp_ExistsCheck = 1
            //   b. Ip不为空
            //   c. IP库原始数据存在
            //   d. LoginSafe_PcUserFirstLogin_AutoAuthSuccess = 0 或者 LoginSafe_PcUserFirstLogin_AutoAuthSuccess = 1 && 用户不是第一次登录（用户IP区域认证数据存在）
            //   e. 用户IP区域认证数据存在
            //   f. IP 黑名单验证. 参见4【身份认证】、【拒绝登录】

            //5.7) IP区域状态验证; LoginSafe_PcIp_AuthStatusCheck, LoginSafe_PcIp_AuthFailAction
            //【身份认证】: NeedIdentityVerify_LoginSafe_VerifyIPAreaStatus
            //   a. LoginSafe_PcIp_ExistsCheck = 1
            //   b. Ip不为空
            //   c. IP库原始数据存在
            //   d. LoginSafe_PcUserFirstLogin_AutoAuthSuccess = 0 或者 LoginSafe_PcUserFirstLogin_AutoAuthSuccess = 1 && 用户不是第一次登录（用户IP区域认证数据存在）
            //   e. 用户IP区域认证数据存在
            //   f. LoginSafe_PcIp_AuthStatusCheck = 1 && IP区域认证数据.AuthStatus <> 200 && LoginSafe_PcIp_AuthFailAction = 100    

            //6. 用户最后一次token所在IP区域认证检查
            //【身份认证】: NeedIdentityVerify_LoginSafe_VerifyIpAreaLastAuthTime
            //   a. LoginSafe_PcToken_Check = 1
            //   b. 最后一次Ip区域token认证时间 {0} 大于等于{1}天，执行身份验证 => LoginSafe_PcToken_LastAuthDay
            // </summary>
#endregion
//            var pcSortedList = new SortedList<int, SafeVerifyStrategyBase>();
//            pcSortedList.Add(0,new PcSafeVerify.PcSafeCfgSwitchVerify());//1,检查总开关
//            pcSortedList.Add(1, new CommonStrategy.SafePartialUserModeVerify());  //2,检查部分策略启用安全认证策略
//            pcSortedList.Add(2, new PcSafeVerify.LoginPasswordHistoryVerify());//3.登录历史密码错误检查
//            pcSortedList.Add(10, new PcSafeVerify.IpBlackListVerify());//4.IP 黑名单检查       
//            pcSortedList.Add(11, new PcSafeVerify.IpAreaVerify());   //5.IP区域检查 （存在性，认证状态）              
//            pcSortedList.Add(21, new PcSafeVerify.TokenLastTimeVerify()); //6.用户最后一次IP区域认证时间检查            
//            ActionList.Add(Default, pcSortedList);
            //TODO 注册APP端登录安全策略
#region
            //<summary>
            //APP端登录安全策略
            //1. 总开关检查; LoginSafe_App_Open;
            //2. 检查部分策略启用安全认证策略; LoginSafe_AppPartial_Mode
            //3. 登录历史密码错误检查; LoginSafe_AppLoginPas_Check, LoginSafe_AppLoginPas_CheckSpec（计数器服务、mongodb统计数据--Ymt_LoginHistory.LoginHistory） 
            //【身份认证】: NeedIdentityVerify_LoginPasswordHistoryVerify
            //   a. LoginSafe_AppLoginPas_Check = 1
            //   b. 登录历史密码错误-3分钟内大于等于5 => LoginSafe_AppLoginPas_CheckSpec

            //4. IP 黑名单验证; LoginSafe_AppIpBlacklist_Check; (mongodb-Ymt_BlacklistUser_201410.YmatouBlacklist_Ip), LoginSafe_AppIpBlacklist_BlacklistAction
            //【身份认证】: NeedIdentityVerify_LoginSafe_BlackIPVerify
            //   a. LoginSafe_AppIpBlacklist_Check = 1
            //   b. IP禁止访问时间未过期，不在白名单，LoginSafe_AppIpBlacklist_BlacklistAction = 100

            //5. IP区域检查; 
            //1) LoginSafe_AppIp_ExistsCheck
            //2) 根据Ip获取IP区域原始数据,不存在则不需要身份验证
            //3) 开启用户第一次登录（LoginSafe_AppUserFirstLogin_AutoAuthSuccess），自动初始化该IP为常用登录Ip; mysql-ymatouusersafe.useripauth  
            //4) 获取IP区域认证数据,不存在则需要身份验证 -- LoginSafe_PcIp_NotExistsIdentityVerify
            //【身份认证】: NeedIdentityVerify_LoginSafe_CannotFindIpArea
            //   a. LoginSafe_AppIp_ExistsCheck = 1
            //   b. Ip不为空
            //   c. IP库原始数据存在
            //   d. LoginSafe_AppUserFirstLogin_AutoAuthSuccess = 0 或者 LoginSafe_AppUserFirstLogin_AutoAuthSuccess = 1 && 用户不是第一次登录（用户IP区域认证数据存在）
            //   e. 用户IP区域认证数据不存在 && LoginSafe_PcIp_NotExistsIdentityVerify = 100


            //5) 是否开启IP区域认证状态检查, LoginSafe_AppIp_AuthStatusCheck
            //6) IP 黑名单验证, LoginSafe_AppIpBlacklist_Check, LoginSafe_AppIpBlacklist_BlacklistAction
            //7) IP区域状态验证; LoginSafe_AppIp_AuthFailAction, LoginSafe_AppIp_AuthSuccessAction
            //【身份认证】: NeedIdentityVerify_LoginSafe_VerifyIPAreaStatus
            //   a. LoginSafe_AppIp_ExistsCheck = 1
            //   b. Ip不为空
            //   c. IP库原始数据存在
            //   d. LoginSafe_AppUserFirstLogin_AutoAuthSuccess = 0 或者 LoginSafe_AppUserFirstLogin_AutoAuthSuccess = 1 && 用户不是第一次登录（用户IP区域认证数据存在）
            //   e. 用户IP区域认证数据存在
            //   f. LoginSafe_AppIp_AuthStatusCheck = 1 && IP区域认证数据.AuthStatus <> 200 && LoginSafe_AppIp_AuthFailAction = 100

            //6. 设备号黑名单检查; LoginSafe_AppBlacklist_Check
            //   mongodb-Ymt_BlacklistUser_201410.YmatouBlacklist_Ip，未过期，LoginSafe_AppBlacklist_BlacklistAction
            //  【身份认证】: NeedIdentityVerify_LoginSafe_VerifyBlackDevice
            //   a. LoginSafe_AppBlacklist_Check = 1
            //   b. ClientId和DeviceId不都为空
            //   c. 设备号在黑名单不在白名单，且禁止登录时间未到期
            //   d. LoginSafe_AppBlacklist_BlacklistAction = 100

            //7. 设备号检查（存在性，认证状态）
            //1) LoginSafe_AppDevice_ExistsCheck
            //2) 设备号，ClientId都为空, 返回LoginSafe_AppDevice_NotExists（400）
            //【身份认证】: NeedIdentityVerify_LoginSafe_DeviceAndCLientIdNotExists
            //   a. LoginSafe_AppDevice_ExistsCheck = 1
            //   b. 设备号，ClientId都为空
            //   c. LoginSafe_AppDevice_NotExists = 100

            //3) 开启用户第一次登录（LoginSafe_AppUserFirstLogin_AutoAuthSuccess），自动初始化该设备号为常用登录设备号（ymatouusersafe.userdeviceauth）
            //4) 设备号不为空, 设备号不存在， LoginSafe_AppDevice_NotExists
            //5) 验证设备号认证状态, LoginSafe_AppDevice_StatusCheck, LoginSafe_AppDevice_AuthSuccessAction, LoginSafe_AppDevice_AuthFailAction
            //【身份认证】: NeedIdentityVerify_LoginSafe_VerifyDeviceStatus
            //   a. LoginSafe_AppDevice_ExistsCheck = 1
            //   b. 设备号不为空, 设备号存在
            //   c. 设备号认证数据.AuthStatus <> 200
            //   c. LoginSafe_AppDevice_AuthFailAction = 100 


            //6) 设备号为空、ClientId不为空, LoginSafe_AppClientId_ExistsCheck；ClientId不存在-> ContinueNextVerify、ClientId存在, LoginSafe_AppClientId_AuthFailAction, LoginSafe_AppClientId_AuthSuccessAction
            //【身份认证】: NeedIdentityVerify_LoginSafe_VerifyClientIdStatus
            //   a. LoginSafe_AppDevice_ExistsCheck = 1
            //   b. 设备号为空, ClientId存在
            //   c. ClientId.AuthStatus <> 200
            //   c. LoginSafe_AppClientId_AuthFailAction = 100 

            //8. 用户最后一次token所在IP区域认证检查, LoginSafe_AppIpUserToken_Check
            //1) IP区域原始数据不存在，允许登录
            //2) 获取IP区域认证数据,不存在则允许登录
            //3) 用户{0}最后一次Ip区域token认证时间{1}大于等于{90}天，执行身份验证; LoginSafe_AppToken_LastAuthDay
            // </summary>
#endregion
//            var appSortedList = new SortedList<int, SafeVerifyStrategyBase>();
//            appSortedList.Add(0, new AppSafeVerify.AppSafeCfgSwitchVerify());    //1.检查总开关
//            appSortedList.Add(1, new AppSafeVerify.SafeAppPartialUserVerify());    //2.APP端部分用户启用分控           
//            appSortedList.Add(100, new AppSafeVerify.LoginPasswordHistoryVerify()); //3.登录历史密码错误检查
//            appSortedList.Add(110, new AppSafeVerify.IpBlackListVerify()); //4.IP黑名单检查
//            appSortedList.Add(200, new AppSafeVerify.IpAreaVerify());   //5.IP区域检查 （存在性，认证状态）
//            appSortedList.Add(300, new AppSafeVerify.DeviceBlacklistVerify()); //6.设备号黑名单检查
//            appSortedList.Add(400, new AppSafeVerify.DeviceVerify());   //7.设备号检查（存在性，认证状态）        
//            appSortedList.Add(500, new AppSafeVerify.AppTokenLastTimeCheck()); //8.用户最后一次IP区域认证时间检查
//            ActionList.Add(App, appSortedList);
            //
            //买手PC端登录风控
            var sellerPcSortedList = new SortedList<int, SafeVerifyStrategyBase>();
            sellerPcSortedList.Add(0, new SellerPcSafeHandle.PcSafeCfgSwitchVerify());//1,检查总开关
            //sellerPcSortedList.Add(1, new CommonStrategy.SafePartialUserModeVerify());  //2,检查部分策略启用安全认证策略
            sellerPcSortedList.Add(2, new SellerPcSafeHandle.LoginPasswordHistoryVerify());//3.登录历史密码错误检查
            sellerPcSortedList.Add(10, new SellerPcSafeHandle.IpBlackListVerify());//4.IP 黑名单检查       
            sellerPcSortedList.Add(11, new SellerPcSafeHandle.IpAreaVerify());   //5.IP区域检查 （存在性，认证状态）              
            sellerPcSortedList.Add(21, new SellerPcSafeHandle.TokenLastTimeVerify()); //6.用户最后一次IP区域认证时间检查            
            ActionList.Add(SellerPc, sellerPcSortedList);
            //
            //买手APP端登录风控
            //TODO 注册买手APP登录风控处理程序
            //
            //买家PC端登录风控策略
            var buyerPcLoginVerifyList = new SortedList<int, SafeVerifyStrategyBase>();
            buyerPcLoginVerifyList.Add(0, new BuyerPcSafeHandle.CheckEnableSafe());
            buyerPcLoginVerifyList.Add(1, new CommonStrategy.SafePartialUserModeVerify());
            buyerPcLoginVerifyList.Add(10,new BuyerPcSafeHandle.TokenVerify());
            buyerPcLoginVerifyList.Add(20,new BuyerPcSafeHandle.IpBlackListVerify());
            buyerPcLoginVerifyList.Add(30, new BuyerPcSafeHandle.LoginFailHistoryVerify());
            buyerPcLoginVerifyList.Add(40, new BuyerPcSafeHandle.IpAreaVerify());
            ActionList.Add(BuyerPc,buyerPcLoginVerifyList);
            //买家app端登录风控
            var buyerAppLoginVerifyList = new SortedList<int, SafeVerifyStrategyBase>();
            buyerAppLoginVerifyList.Add(0, new BuyerAppSafeHandle.CheckEnableSafe());
            buyerAppLoginVerifyList.Add(1, new CommonStrategy.SafePartialUserModeVerify());
            buyerAppLoginVerifyList.Add(10, new BuyerAppSafeHandle.TokenVerify());
            buyerAppLoginVerifyList.Add(20, new BuyerAppSafeHandle.DeviceBlacklistVerify());
            buyerAppLoginVerifyList.Add(30, new BuyerAppSafeHandle.LoginFailHistoryVerify());
            buyerAppLoginVerifyList.Add(40, new BuyerAppSafeHandle.DeviceStatusVerify());
            buyerAppLoginVerifyList.Add(50, new BuyerAppSafeHandle.IpAreaVerify());
            ActionList.Add(BuyerApp, buyerAppLoginVerifyList);

            //默认处理策略
            var defaultVerifyList = new SortedList<int, SafeVerifyStrategyBase>();
            defaultVerifyList.Add(0, new DefaultSafeHandle._DefaultNeedVerifyHandle());
            ActionList.Add(Default, defaultVerifyList);
            //
            var defaultVerifyList2 = new SortedList<int, SafeVerifyStrategyBase>();
            defaultVerifyList2.Add(0, new DefaultSafeHandle._DefaultSkipVerifyHandle());
            ActionList.Add(SkipVerify, defaultVerifyList2);
            YmatouLoggingService.Debug("buyer,seller pc,app login safe register ok.");
        }

        public static string GetStrategyKey(string source, byte userType)
        {
            //
            if (source.IsEmpty()) return Default;
            //买家
            var sourceLower = source.ToLower();
            if (userType == 0)
            {
                var buyerAppSource = "BuyerAppSource".GetAppSettingValus("app");
                if (buyerAppSource.Any(c => c == sourceLower)) return BuyerApp;
                else return BuyerPc;
            }
            //买手
            if (userType == 1)
            {
                //seller app 登录风控策略(目前买手登录只走PC端策略)
                /*var sellerAppSource = "SellerAppSource".GetAppSettingValus("seller.app.ymatou.com");
                if (sellerAppSource.Any(c => c == sourceLower))
                    return /*SellerApp;*/
                return SellerPc;
            }
            //其他类型用户
            return SkipVerify;
        }

        public static string GetStrategyKey(string source)
        {
            if (source.IsEmpty()) return "pc";
            if (source.ToLower() == "app") return "app";
            return "pc";
        }
       
        public static void Clear()
        {
           ActionList.Clear();
        }

        public static AuthSafeHandleCode AuthSafeHandleExecute(
            UserLoginParameter parameter
            , UserLoginAuthRepository repo
            , AuthSafeConfiguration cfg
            , byte userType)
        {
            var strategyType = GetStrategyKey(parameter.Source,userType);
            parameter.StrategyType = strategyType;

            var action = ActionList.TryGetV(strategyType, new SortedList<int, SafeVerifyStrategyBase>());
            var index = 0;
            foreach (var a in action.Values)
            {
                try
                {
                    var watch = Stopwatch.StartNew();
                    var code = a.Execute(parameter, repo, cfg);
                    watch.Stop();
                    YmatouLoggingService.Debug("[AuthSafeHandleExecute] {0}.{1} Execute end，result {6}，run {2} ms，par,{3},{4},{5}，rId:{7}",
                        index++,a.ToString(), watch.ElapsedMilliseconds
                        , parameter.Source, parameter.LoginId, parameter.UserId
                        , code.ToString(), parameter.RequestId);
                    if (code.Code != AuthSafeHandleCode.ContinueNextVerify) return code;
                }
                catch (Exception ex)
                {
                    YmatouLoggingService.Error("rId: {0} 用户 {1} 登录 {2} 当前风控命令失败，继续执行下条风控命令 {3}", parameter.RequestId, parameter.LoginId, parameter.Source, ex);
                }
            }
            //
            return AuthSafeHandleCode.CreateCode(AuthSafeHandleCode.AllowLogin);
        }
    }
}
